package org.geometerplus.fbreader.formats;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.text.TextUtils;

import com.example.administrator.fangbook.dataLibrary.book.ShelfItemBook;
import com.example.administrator.fangbook.utils.ToastUtils;

import org.geometerplus.fbreader.book.ReadBook;
import org.geometerplus.fbreader.bookmodel.BookModel;
import org.geometerplus.fbreader.fbreader.FBReaderApp;
import org.geometerplus.fbreader.formats.m17k.MTxtNovelReader;
import org.geometerplus.fbreader.formats.oeb.MEPubReader;
import org.geometerplus.fbreader.formats.txt.MTxtReader;
import org.geometerplus.zlibrary.core.filesystem.ZL17KPlainTxtFile;
import org.geometerplus.zlibrary.core.filesystem.ZLFile;
import org.geometerplus.zlibrary.core.filesystem.ZLTxtFile;
import org.geometerplus.zlibrary.text.model.ZLTextModel;
import org.geometerplus.zlibrary.ui.android.view.animation.AnimationManager;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * (读取本地章节内容，把文章内容数据解析到bookModel中。
 * 维护ZLTextModel数据缓存
 */
public class BookReader {

    /**
     * 动画管理
     */
    protected AnimationManager myAnimationManager;
    /**
     * 注册功能类
     */
    protected FBReaderApp myApplication;

    /**
     * 安装在内部的格式插件
     */
    protected BuiltinFormatPlugin myFormatPlugin;

    /**
     * 缓存，应该是三个章节的内容
     */
    protected LruCache<ZLFile, ZLTextModel> myCachedModelData = new LruCache<ZLFile, ZLTextModel>(3);

    /**
     * 每个章节 对应加载成功后的回调
     */
    protected HashMap<ZLFile, OnModelDataLoaded> myCallBacks = new HashMap<ZLFile, OnModelDataLoaded>();

    /**
     * 每一章节的内容
     */
    protected List<ZLFile> myLoadingModels = new ArrayList<ZLFile>();

    /**
     * 这个应该是最终绘制需要的数据
     */
    protected BookModel myBookModel;

    /**
     * 当前书的信息
     */
    protected ShelfItemBook myReadingBook;

    /**
     * 当前阅读的章节文件
     */
    protected ZLFile myReadingFile;

    /**
     * 当前工作线程
     */
    private Handler myWorkingHandler;
    private HandlerThread myWorkingThread = null;
    /**
     * 开始、结束--标记
     */
    private final int MSG_START = 0x01;
    private final int MSG_CLOSE = 0x02;


    public static BookReader createReader(FBReaderApp app, ZLFile file) {
        //判断当前文件
        if (file instanceof ZLTxtFile) {
            //txtwenjian
            return new MTxtReader(app, file);
        } else if (file instanceof ZL17KPlainTxtFile) {
            //17k文件
            return new MTxtNovelReader(app, file);
        } else {
            //epub文件
            if ("epub".equalsIgnoreCase(file.getExtension())) {
                return new MEPubReader(app, file);
            } else {
                return new BookReader(app, file);
            }
        }
    }

    protected BookReader(FBReaderApp app, ZLFile file) {
        myReadingFile = file;
        myReadingBook = file.getShelfBook();
        myApplication = app;
        init(file);
    }

    //做一些简单的变量工作。复杂的放到工作线程中执行。
    protected void init(ZLFile file) {

    }

    /**
     * 得到开始的文件
     *
     * @return
     */
    public ZLFile getStartFile() {
        return myReadingFile;
    }

    public void setAnimationManager(AnimationManager animationManager) {
        myAnimationManager = animationManager;
    }

    public AnimationManager getAnimationManager() {
        return myAnimationManager;
    }

    /**
     * 这个方法是调用so文件后，回调的方法
     */
    public void onCreateTextModelSuccess(final ZLTextModel txtModel) {
        if (txtModel == null) {
            return;
        }
        OnModelDataLoaded l = null;
        ZLFile zfile = ZLFile.createFileByUri(txtModel.getId());
        synchronized (this) {
            if (!myLoadingModels.contains(zfile)) {
                myCallBacks.remove(zfile);
                return;
            }
            if (zfile != null) {
                zfile = myLoadingModels.remove(myLoadingModels.indexOf(zfile));
                if (myCachedModelData != null) {
                    myCachedModelData.put(zfile, txtModel);
                }

                l = myCallBacks.remove(zfile);
            }

        }
        if (l != null) {
            final OnModelDataLoaded callBack = l;
            final ZLFile readingFile = zfile;
            //所有native层回调，都放到work线程执行
            myWorkingHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onLoadedSuccess(readingFile, txtModel);
                }
            });
        }
    }


    /**
     * 创建文件模型失败
     *
     * @param file
     * @param errMsg
     */
    public void onCreateTextModelFailed(ZLFile file, final String errMsg) {
        synchronized (this) {
            //回调移除
            myCallBacks.remove(file);
            //当前加载的file移除
            myLoadingModels.remove(file);
        }
        //主线程Toast
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                ToastUtils.show(errMsg);
            }
        });
    }

    /**
     * 读取模型数据
     * 转换数据调native;
     *
     * @param file
     * @param callBack
     * @throws BookReadingException
     */
    protected void readModelData(ZLFile file, OnModelDataLoaded callBack) throws BookReadingException {
        if (file == null) {
            throw new BookReadingException("参数不正确");
        }
        try {
            synchronized (this) {
                if (callBack != null) {
                    //添加文件回调
                    myCallBacks.put(file, callBack);
                }
                if (!myLoadingModels.contains(file)) {
                    //添加加载file
                    myLoadingModels.add(file);
                }
            }
            if (null != myAnimationManager) {
                //是新的一章
//                myAnimationManager.isNewChapter = true;
            }
            //底层插件读取 书籍
            myFormatPlugin.readModel(file, myBookModel);

        } catch (BookReadingException e) {
            onCreateTextModelFailed(file, e.getLocalizedMessage());
        }
    }


    /**
     * t_read_work_thread 工作线程，查看这些线程的作用和任务，都具体负责工作
     */
    public synchronized void start() {
        if (myWorkingHandler != null && myWorkingThread.isAlive()) {
            myWorkingThread.quit();
        }
        myWorkingThread = new HandlerThread("t_read_work_thread");//初始化当前的工作线程，用来初始化解析插件，
        //处理线程的非受检异常（当一个线程由于发生了非受检异常而终止时，
        // JVM会使用Thread.gerUncaughtExceptionHandler()方法查看该线程上的UncaughtExceptionHandler，
        // 并调用他的uncaughtException()方法）
        myWorkingThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable) {
                new RuntimeException(throwable).printStackTrace();
            }
        });
        myWorkingThread.start();
        Looper looper = myWorkingThread.getLooper();
        if (looper != null) {
            //子线程将文件转换为书籍信息加载
            myWorkingHandler = new Handler(looper) {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == MSG_START) {
                        if (myApplication != null) {
                            //根据文件得到对应的插件
                            myFormatPlugin = (BuiltinFormatPlugin) PluginCollection.Instance(myApplication.mSystemInfo).getPlugin(myReadingFile);
                            //把文件和插件
                            ReadBook readBook = ReadBook.getByFile(myReadingFile, myFormatPlugin);
                            myBookModel = new BookModel(readBook);
                            myApplication.setBookModel(myBookModel);
                            myFormatPlugin.init(BookReader.this, myBookModel);
                            if (myReadingFile != null) {
                                doStartRead(myReadingFile);
                            }
                        }
                    } else if (msg.what == MSG_CLOSE) {
                        doClose();
                    }

                }
            };
        }
        if (myWorkingHandler != null) {
            myWorkingHandler.sendEmptyMessage(MSG_START);
        }

    }

    /**
     * 去开始阅读
     *
     * @param file
     */
    protected void doStartRead(ZLFile file) {
        if (file.exists()) {
            //文件存在
            //读取模型数据
            readModelData(file, new OnModelDataLoaded() {
                @Override
                public void onLoadedSuccess(final ZLFile file, final ZLTextModel model) {
                    if (file instanceof ZL17KPlainTxtFile) {
                        ZL17KPlainTxtFile f = (ZL17KPlainTxtFile) file;
                        if (!TextUtils.isEmpty(f.getChapterId())) {
                            if (myApplication != null && myApplication.Model != null && myApplication.Model.Book != null && myApplication.Model.Book.getReader() != null) {
//                                MTxtNovelReader txtReader = (MTxtNovelReader) reader.Model.Book.getReader();
//                                Chapter chapter = txtReader.loadChapterById(f.getChapterId());
//                                if (!file.exists() || chapter.isVIP() == 0) {
//                                    txtReader.gotoChapter(file, null);
//                                } else {
//                                    onModelDataLoadedSuccess(file, model);
//                                    Chapter c = new Chapter();
//                                    c.setBookId(f.getBookId());
//                                    c.setId(f.getChapterId());
//                                    txtReader.readChapterSuccess(c);
//                                }
                            }
                        }
                    } else {
                        onModelDataLoadedSuccess(file, model);
                    }
                }

                @Override
                public void onLoadedFailed(ZLFile file, String errorMsg) {
                    myAnimationManager.loadFailed(file, errorMsg);
                }
            });
        }
    }

    protected void onModelDataLoadedSuccess(final ZLFile file, final ZLTextModel model) {
        myAnimationManager.setModel(file, model);
    }


    //native层释放资源
    private synchronized void doClose() {
//        PluginCollection.deleteInstance();
//        if (myWorkingThread != null && myWorkingThread.isAlive()) {
//            myWorkingThread.quit();
//        }
//        myFormatPlugin = null;
//        //解决size不一致问题，导致的crash
//        if (myCachedModelData.size() > 0) {
//            try {
//                myCachedModelData.evictAll();
//            } catch (Exception e) {
//
//            }
//            myCachedModelData = null;
//        }
//        myCallBacks.clear();
//        myCallBacks = null;
//        myLoadingModels.clear();
//        myLoadingModels = null;
//        myReadingBook = null;
//        myApplication = null;
//        myReadingBook = null;
//        myReadingFile = null;
//        if (myBookModel != null) {
//            myBookModel.destroy();
//            myBookModel = null;
//
//        }
//        myWorkingHandler = null;
//        myWorkingThread = null;
    }

    /**
     * 在work线程执行native层调用
     *
     * @param r
     * @param isHighProprity 是否提高优先级
     */
    protected synchronized void runOnBackground(Runnable r, boolean isHighProprity) {
        if (myWorkingHandler != null) {
            if (isHighProprity) {
                //提高优先级
                myLoadingModels.clear();
                myWorkingHandler.removeCallbacksAndMessages(null);
                myWorkingHandler.postAtFrontOfQueue(r);
            } else {
                myWorkingHandler.post(r);
            }
        }
    }

    public synchronized void destroy() {
        if (myWorkingHandler != null) {
            myWorkingHandler.removeCallbacksAndMessages(null);
            myWorkingHandler.sendEmptyMessage(MSG_CLOSE);
        }
    }


    public class BookFileNotFoundException extends BookReadingException {
        public BookFileNotFoundException(ZLFile file) {
            super("章节文件不存在！路径：" + file.getPath());
        }
    }

    public interface OnModelDataLoaded {
        void onLoadedSuccess(ZLFile file, ZLTextModel model);

        void onLoadedFailed(ZLFile file, String errorMsg);
    }

    abstract class OnBookReaderListener implements OnModelDataLoaded {
        @Override
        public void onLoadedSuccess(ZLFile file, ZLTextModel model) {
        }

        @Override
        public void onLoadedFailed(ZLFile file, String errorMsg) {

        }
    }
}
